using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

namespace NikonGuyDesktopLib
{
    /// <summary>
    /// Summary description for ImageFrame.
    /// </summary>
    public class ImageFrame : IDisposable
    {
        public Bitmap _image;
        public Bitmap _imageReflection;
        public Bitmap Image
        {
            get
            {
                return _image;
            }
            set
            {
                _image = value;
            }
        }

        public float _rotation;
        public float Rotation
        {
            get
            {
                return _rotation;
            }
            set
            {
                _rotation = value;
            }
        }

        public Point _location;
        public Point Location
        {
            get
            {
                return _location;
            }
            set
            {
                _location = value;
            }
        }

        private int _maxDimLength;
        private int BORDER_SIZE = 4;

        public static float REFLECTION_LENGTH = 0.60f;

        public bool VALID = true;

        private Rectangle _frameRect;
        private Rectangle _imageRect;

        public Rectangle Bounds
        {
            get
            {
                return new Rectangle(Location, new Size(_frameRect.Width, (int)(_frameRect.Height * (1 + REFLECTION_LENGTH))));
            }
        }
        public Rectangle ReflectionBounds
        {
            get
            {
                return new Rectangle(new Point(Location.X,Location.Y + _frameRect.Height), new Size(_frameRect.Width, (int)(_frameRect.Height * (REFLECTION_LENGTH))));
            }
        }

        // Places and rotates randomly
        public ImageFrame(Image image, Rectangle area, int MaxDimLength, Random r, ArrayList imageFrames)
        {
            _maxDimLength = MaxDimLength;

            Rectangle rect = new Rectangle(0, 0, image.Width, image.Height);
            if (image.Width > image.Height && image.Width > _maxDimLength)
            {
                rect.Width = _maxDimLength;
                rect.Height = image.Height * _maxDimLength / image.Width;
            }
            else if (image.Height > image.Width && image.Height > _maxDimLength)
            {
                rect.Height = _maxDimLength;
                rect.Width = image.Width * _maxDimLength / image.Height;
            }

            // 20% pad & 120% pad
            int xW = (int) (area.Width - (rect.Width * 1.4));
            int yH = (int)(area.Height - (rect.Height * 1.4));
            //yH = (int)(0.7f * (area.Height - (rect.Height * 1.4)));// - REFLECTION_LENGTH * MaxDimLength);
			yH = (int)((area.Height - (rect.Height * 1.4)) - REFLECTION_LENGTH * MaxDimLength);

            int x = r.Next(xW);
            int y = r.Next(yH);
            //int yDiff = (int)(0.3f * (area.Height - (rect.Height * 1.4)));
			int yDiff = (int)((area.Height - (rect.Height * 1.4)));
            //y += yDiff;

            //_maxDimLength = (int)(MaxDimLength * (0.3f + (0.7f * (y-yDiff) / (yH))));
			//_maxDimLength = (int)(MaxDimLength * (0.3f + (0.7f * (y-yDiff) / (yH))));
			_maxDimLength = (int)(MaxDimLength * (0.3f + (0.7f * (y) / (yH))));
            if (image.Width > image.Height && image.Width > _maxDimLength)
            {
                rect.Width = _maxDimLength;
                rect.Height = image.Height * _maxDimLength / image.Width;
            }
            else if (image.Height > image.Width && image.Height > _maxDimLength)
            {
                rect.Height = _maxDimLength;
                rect.Width = image.Width * _maxDimLength / image.Height;
            }

            _location = new Point((int)(x + 0.2 * rect.Width), (int)(y + 0.2 * rect.Height));

            _frameRect = rect;

            bool good = false;
            int i = 0;
            while (!good && i < 10000)
            {
                good = true;
                foreach (ImageFrame imf in imageFrames)
                {
                    if (imf != this && collide(this, imf))
                    {
                        good = false;
                    }
                }
                if (!good)
                {
                    x = r.Next(xW);
                    y = r.Next(yH);
                    //y += yDiff;

                    //_maxDimLength = (int)(MaxDimLength * (0.3f + (0.7f * (y - yDiff) / (yH))));
					_maxDimLength = (int)(MaxDimLength * (0.3f + (0.7f * (y) / (yH))));
                    if (image.Width > image.Height && image.Width > _maxDimLength)
                    {
                        rect.Width = _maxDimLength;
                        rect.Height = image.Height * _maxDimLength / image.Width;
                    }
                    else if (image.Height > image.Width && image.Height > _maxDimLength)
                    {
                        rect.Height = _maxDimLength;
                        rect.Width = image.Width * _maxDimLength / image.Height;
                    }

                    _location = new Point((int)(x + 0.2 * rect.Width), (int)(y + 0.2 * rect.Height));

                    _frameRect = rect;
                }
                i++;
            }

            if (i >= 1000)
            {
                VALID = false;
            }

            _imageRect = new Rectangle(rect.X + BORDER_SIZE, rect.Y + BORDER_SIZE, rect.Width - 2 * BORDER_SIZE, rect.Height - 2 * BORDER_SIZE); ;

            _image = imageResize(image, _imageRect.Size);
            
            generateImages(rect);
        }

        private void generateImages(Rectangle rect)
        {
            try
            {
                _imageReflection = new Bitmap(_image);//.Clone(new Rectangle(0, 0, _image.Height, _image.Width), PixelFormat.Format32bppArgb);
                _imageReflection.RotateFlip(RotateFlipType.Rotate180FlipX);
                Bitmap gradient = new Bitmap(_imageReflection.Width, _imageReflection.Height,PixelFormat.Format32bppArgb);
                Graphics new_g = Graphics.FromImage(gradient);
                Rectangle rect4 = new Rectangle(0, 0, gradient.Width, gradient.Height);
                LinearGradientBrush linearBrush = new LinearGradientBrush(rect4, Color.FromArgb(60,0,0,0),
                    Color.FromArgb(0, 0, 0, 0), LinearGradientMode.Vertical);
                new_g.FillRectangle(linearBrush, rect);
                BitmapData gbd = gradient.LockBits(rect4, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
                BitmapData ibd = _imageReflection.LockBits(rect4, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
                unsafe
                {

                    for (int i = 0; i < gbd.Height; i++)
                    {

                        byte* destRowPtr = (byte*)ibd.Scan0.ToPointer() + (ibd.Stride * i);

                        byte* srcRowPtr = (byte*)gbd.Scan0.ToPointer() + (gbd.Stride * i);

                        for (int j = 0; j < gbd.Width; j++)
                        {

                            destRowPtr[(j * 4) + 3] = srcRowPtr[(j * 4) + 3];

                        }

                    }

                }// /unsafe  
                gradient.UnlockBits(gbd);
                gradient.Dispose();
                _imageReflection.UnlockBits(ibd);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                VALID = false;
            }
        }

        public static bool collide(ImageFrame imfNew, ImageFrame imf)
        {
            return imf.Bounds.IntersectsWith(imfNew.ReflectionBounds);
        }

        private static Bitmap imageResize(Image src_image, Size maxSize)
        {
            if (src_image == null)
                return null;

            // decide what the new actual dimensions of the image will be
            //Size new_size = getNewSize(src_image.Size, maxSize);
            Size new_size = maxSize;
            Bitmap resized_image = null;
            Graphics new_g = null;

            try
            {
                // create a new bitmap to use for generation of the resized image
                //resized_image = new Bitmap(new_size.Width, new_size.Height, src_image.PixelFormat);

                // Not sure about this whole pixel format thing
                resized_image = new Bitmap(new_size.Width, new_size.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                new_g = Graphics.FromImage(resized_image);
                new_g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                new_g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                new_g.DrawImage(src_image, 0, 0, resized_image.Width, resized_image.Height);
            }
            catch (System.OutOfMemoryException oome)
            {
                // need to log this somehow...


            }
            finally
            {

                // release memory for the two objects
                if (src_image != null)
                {
                    src_image.Dispose();
                }

                if (new_g != null)
                    new_g.Dispose();

            }

            return resized_image;
        }

        public void Paint(Graphics g)
        {
            //g.SmoothingMode = SmoothingMode.AntiAlias;
            g.ResetTransform();
            ImageAttributes ia = new ImageAttributes();

            g.TranslateTransform(Location.X, Location.Y, MatrixOrder.Append);

            g.SmoothingMode = SmoothingMode.AntiAlias;
            Color upLeft = _image.GetPixel(0,0);
      
//            if (false && !_animating && (upLeft.R < 250 || upLeft.G < 250 || upLeft.B < 250))
//            {
//                g.FillRectangle(Brushes.White, _frameRect);
//            }

            try
            {
                g.DrawImage(_image,_imageRect,0,0,_image.Width,_image.Height,GraphicsUnit.Pixel,ia);

                g.TranslateTransform(0, _image.Height);
          
                Rectangle rect = new Rectangle();
                rect.X = _imageRect.X;
                rect.Y = _imageRect.Y;
                rect.Width = _imageRect.Width;
                rect.Height = (int)(_imageRect.Height * REFLECTION_LENGTH);
          
                //g.DrawImage(_imageReflection, rect, 0, 0, _imageReflection.Width, _imageReflection.Height, GraphicsUnit.Pixel, ia);
				int anglex = (int)(Math.Sin(Math.PI / 18.0) * rect.Height);
				Point[] points = new Point[] {new Point(rect.X,rect.Y),new Point(rect.X + rect.Width,rect.Y), new Point(rect.X + anglex,rect.Y + rect.Height)};
				g.DrawImage(_imageReflection, points, new Rectangle(0, 0, _imageReflection.Width, _imageReflection.Height), GraphicsUnit.Pixel, ia);
          
            }
            catch (System.OutOfMemoryException oome)
            {
                // need to log this somehow...


            }

            g.ResetTransform();
        }

        public void Dispose()
        {
            if (_image != null)
            {
                _image.Dispose();
            }
        }
    }
}

